package com.mathlearning.auth.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mathlearning.auth.common.BusinessException;
import com.mathlearning.auth.dto.problem.*;
import com.mathlearning.auth.common.ApiResponse;
import com.mathlearning.auth.entity.*;
import com.mathlearning.auth.repository.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class ProblemService {

    private static final Logger logger = LoggerFactory.getLogger(ProblemService.class);

    @Autowired
    private CourseRepository courseRepository;

    @Autowired
    private ChapterRepository chapterRepository;

    @Autowired
    private ProblemRepository problemRepository;

    @Autowired
    private UserSubmissionRepository submissionRepository;

    @Autowired
    private UserProgressRepository progressRepository;

    @Autowired
    private ProblemFavoriteRepository favoriteRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private DailyProblemPoolService problemPoolService;

    @Autowired
    private org.springframework.data.redis.core.RedisTemplate<String, Object> redisTemplate;

    private final ObjectMapper objectMapper = new ObjectMapper();
    
    private static final int RECENT_PROBLEMS_SIZE = 10; // 记录最近10道题

    /**
     * 获取课程列表（包含章节信息）
     */
    public List<CourseResponse> getCourses() {
        List<Course> courses = courseRepository.findAllByOrderByCreateTimeAsc();

        return courses.stream().map(course -> {
            List<Chapter> chapters = chapterRepository.findByCourseIdOrderByOrderNumAsc(course.getId());

            List<CourseResponse.ChapterInfo> chapterInfos = chapters.stream()
                    .map(ch -> new CourseResponse.ChapterInfo(ch.getId(), ch.getName(), ch.getProblemCount()))
                    .collect(Collectors.toList());

            return new CourseResponse(course.getId(), course.getName(), course.getIcon(),
                    course.getTotalProblems(), chapterInfos);
        }).collect(Collectors.toList());
    }

    /**
     * 获取题目列表
     */
    public ProblemListResponse getProblemList(ProblemListRequest request, Long currentUserId) {
        Pageable pageable = PageRequest.of(request.getPage() - 1, request.getPageSize());
        Page<Problem> page;

        // 根据条件查询（排除已删除的题目）
        if (request.getChapterId() != null) {
            page = problemRepository.findByChapterIdAndDeleted(request.getChapterId(), 0, pageable);
        } else if (request.getCourseId() != null && request.getDifficulty() != null) {
            page = problemRepository.findByCourseIdAndDifficultyAndDeleted(request.getCourseId(), request.getDifficulty(), 0, pageable);
        } else if (request.getCourseId() != null) {
            page = problemRepository.findByCourseIdAndDeleted(request.getCourseId(), 0, pageable);
        } else {
            page = problemRepository.findByDeleted(0, pageable);
        }

        // 转换为DTO
        List<ProblemListResponse.ProblemItem> list = page.getContent().stream()
                .map(p -> toProblemItem(p, currentUserId))
                .collect(Collectors.toList());

        // 如果有status筛选，进一步过滤
        if (request.getStatus() != null && currentUserId != null) {
            list = filterByStatus(list, request.getStatus());
        }

        return new ProblemListResponse(page.getTotalElements(), list);
    }

    /**
     * 获取题目详情
     */
    public ProblemDetailResponse getProblemDetail(Long problemId, Long currentUserId) {
        Problem problem = problemRepository.findById(problemId)
                .orElseThrow(() -> new BusinessException("题目不存在"));

        return toProblemDetailResponse(problem, currentUserId);
    }

    /**
     * 提交答案
     */
    @Transactional
    public SubmitResultResponse submitAnswer(Long userId, SubmitAnswerRequest request) {
        Problem problem = problemRepository.findById(request.getProblemId())
                .orElseThrow(() -> new BusinessException("题目不存在"));

        // 判断答案
        SubmitResult result = judgeAnswer(problem, request.getAnswer(), request.getProcess());

        // 创建提交记录
        UserSubmission submission = new UserSubmission();
        submission.setUserId(userId);
        submission.setProblemId(request.getProblemId());
        submission.setAnswer(request.getAnswer());
        submission.setProcess(request.getProcess());
        submission.setStatus(result.getStatus());
        submission.setScore(result.getScore());
        submission.setFeedback(result.getFeedback());
        submission = submissionRepository.save(submission);

        // 更新题目统计
        problem.setSubmitCount(problem.getSubmitCount() + 1);
        if ("accepted".equals(result.getStatus())) {
            problem.setAcceptedCount(problem.getAcceptedCount() + 1);
        }
        updateAcceptanceRate(problem);
        problemRepository.save(problem);

        // 如果首次通过，更新学习进度
        if ("accepted".equals(result.getStatus())) {
            boolean firstAccepted = !submissionRepository.existsByUserIdAndProblemIdAndStatus(
                    userId, request.getProblemId(), "accepted");
            if (firstAccepted) {
                updateProgress(userId, problem.getCourseId());
            }
        }

        // 更新连续学习天数
        updateContinuousLearningDays(userId);

        // 累加学习时长（每题固定5分钟）
        updateStudyMinutes(userId, 5);

        logger.info("用户 {} 提交题目 {} 答案，状态：{}", userId, request.getProblemId(), result.getStatus());

        return new SubmitResultResponse(
                submission.getId(),
                result.getStatus(),
                result.getScore(),
                problem.getCorrectAnswer(),
                result.getFeedback(),
                submission.getSubmitTime()
        );
    }

    /**
     * 获取题解
     */
    public ProblemDetailResponse.Example getSolution(Long problemId, Long currentUserId) {
        Problem problem = problemRepository.findById(problemId)
                .orElseThrow(() -> new BusinessException("题目不存在"));

        // 检查用户是否有权查看题解（已通过或付费查看）
        boolean hasAccepted = submissionRepository.existsByUserIdAndProblemIdAndStatus(
                currentUserId, problemId, "accepted");

        if (!hasAccepted) {
            // 可以在这里添加付费查看题解的逻辑
            throw new BusinessException("请先通过题目后查看题解");
        }

        return new ProblemDetailResponse.Example("题解", problem.getSolution(), "详细解答");
    }

    /**
     * 获取题目答案和解答（无条件查看，用于学习）
     */
    public ApiResponse<AnswerAndSolutionResponse> getAnswerAndSolution(Long problemId) {
        Problem problem = problemRepository.findById(problemId)
                .orElseThrow(() -> new BusinessException("题目不存在"));

        AnswerAndSolutionResponse response = new AnswerAndSolutionResponse(
                problem.getId(),
                problem.getTitle(),
                problem.getCorrectAnswer(),
                problem.getSolution(),
                problem.getType(),
                problem.getDifficulty()
        );

        return ApiResponse.success(response);
    }

    /**
     * 收藏/取消收藏题目
     */
    @Transactional
    public FavoriteResponse toggleFavorite(Long userId, Long problemId) {
        if (!problemRepository.existsById(problemId)) {
            throw new BusinessException("题目不存在");
        }

        Optional<ProblemFavorite> existing = favoriteRepository.findByUserIdAndProblemId(userId, problemId);

        if (existing.isPresent()) {
            // 已收藏，取消收藏
            favoriteRepository.delete(existing.get());
            logger.info("用户 {} 取消收藏题目 {}", userId, problemId);
            return new FavoriteResponse(false);
        } else {
            // 未收藏，添加收藏
            ProblemFavorite favorite = new ProblemFavorite();
            favorite.setUserId(userId);
            favorite.setProblemId(problemId);
            favoriteRepository.save(favorite);
            logger.info("用户 {} 收藏题目 {}", userId, problemId);
            return new FavoriteResponse(true);
        }
    }

    /**
     * 获取学习进度
     */
    public ProgressResponse getProgress(Long userId) {
        List<UserProgress> progressList = progressRepository.findByUserId(userId);
        List<Course> courses = courseRepository.findAll();

        int totalSolved = 0;
        int totalCount = 0;

        List<ProgressResponse.CourseProgress> courseProgressList = new ArrayList<>();

        for (Course course : courses) {
            UserProgress progress = progressList.stream()
                    .filter(p -> p.getCourseId().equals(course.getId()))
                    .findFirst()
                    .orElse(null);

            int solved = 0;
            int total = (int) problemRepository.countByCourseId(course.getId());

            if (progress != null) {
                solved = progress.getSolvedCount();
            }

            totalSolved += solved;
            totalCount += total;

            courseProgressList.add(new ProgressResponse.CourseProgress(
                    course.getId(), course.getName(), solved, total
            ));
        }

        BigDecimal percentage = totalCount > 0 ?
                BigDecimal.valueOf((double) totalSolved / totalCount * 100).setScale(1, RoundingMode.HALF_UP) :
                BigDecimal.ZERO;

        return new ProgressResponse(totalSolved, totalCount, percentage, courseProgressList);
    }

    /**
     * 获取提交记录
     */
    public SubmissionListResponse getSubmissions(Long userId, Integer page, Integer pageSize, String status) {
        Pageable pageable = PageRequest.of(page - 1, pageSize);
        Page<UserSubmission> submissionPage;

        if (status != null && !status.isEmpty()) {
            submissionPage = submissionRepository.findByUserIdAndStatusOrderBySubmitTimeDesc(userId, status, pageable);
        } else {
            submissionPage = submissionRepository.findByUserIdOrderBySubmitTimeDesc(userId, pageable);
        }

        List<SubmissionListResponse.SubmissionItem> list = submissionPage.getContent().stream()
                .map(s -> {
                    Problem problem = problemRepository.findById(s.getProblemId()).orElse(null);
                    String title = problem != null ? problem.getTitle() : "题目已删除";
                    return new SubmissionListResponse.SubmissionItem(
                            s.getId(), s.getProblemId(), title, s.getAnswer(), s.getProcess(), 
                            s.getStatus(), s.getScore(), s.getFeedback(), s.getSubmitTime()
                    );
                })
                .collect(Collectors.toList());

        return new SubmissionListResponse(submissionPage.getTotalElements(), list);
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 转换为ProblemItem
     */
    private ProblemListResponse.ProblemItem toProblemItem(Problem problem, Long userId) {
        List<String> tags = parseJsonArray(problem.getTags());
        String status = getUserProblemStatus(userId, problem.getId());

        return new ProblemListResponse.ProblemItem(
                problem.getId(),
                problem.getTitle(),
                problem.getDifficulty(),
                problem.getAcceptanceRate(),
                status,
                tags,
                problem.getSubmitCount(),
                problem.getAcceptedCount()
        );
    }

    /**
     * 转换为ProblemDetailResponse
     */
    private ProblemDetailResponse toProblemDetailResponse(Problem problem, Long userId) {
        List<ProblemDetailResponse.Example> examples = parseExamples(problem.getExamples());
        List<String> hints = parseJsonArray(problem.getHints());
        List<String> tags = parseJsonArray(problem.getTags());
        List<ProblemDetailResponse.Option> options = parseOptions(problem.getOptions());

        // 只有通过的用户才能看到题解
        String solution = null;
        if (userId != null && submissionRepository.existsByUserIdAndProblemIdAndStatus(userId, problem.getId(), "accepted")) {
            solution = problem.getSolution();
        }

        return new ProblemDetailResponse(
                problem.getId(),
                problem.getTitle(),
                problem.getDifficulty(),
                problem.getType(),
                problem.getDescription(),
                problem.getInputDescription(),
                problem.getOutputDescription(),
                examples,
                hints,
                tags,
                options,
                problem.getAcceptanceRate(),
                problem.getSubmitCount(),
                problem.getAcceptedCount(),
                solution
        );
    }

    /**
     * 判断答案
     */
    private SubmitResult judgeAnswer(Problem problem, String userAnswer, String process) {
        String correctAnswer = problem.getCorrectAnswer();
        String type = problem.getType();

        userAnswer = userAnswer.trim();

        // 选择题和填空题：完全匹配
        if ("choice".equals(type) || "fill".equals(type)) {
            // 支持多个正确答案（用|分隔）
            String[] possibleAnswers = correctAnswer.split("\\|");
            for (String possible : possibleAnswers) {
                if (userAnswer.equalsIgnoreCase(possible.trim())) {
                    return new SubmitResult("accepted", 100, "回答正确！");
                }
            }
            return new SubmitResult("wrong_answer", 0, "答案错误，正确答案是：" + correctAnswer);
        }

        // 计算题：答案正确给满分，答案错误但有过程给部分分
        if ("calculation".equals(type)) {
            String[] possibleAnswers = correctAnswer.split("\\|");
            for (String possible : possibleAnswers) {
                if (userAnswer.equalsIgnoreCase(possible.trim())) {
                    return new SubmitResult("accepted", 100, "回答正确！解题思路清晰。");
                }
            }

            // 答案错误，但提供了过程
            if (process != null && !process.trim().isEmpty()) {
                return new SubmitResult("partial", 30, "答案错误，但解题过程有一定参考价值。正确答案是：" + correctAnswer);
            }

            return new SubmitResult("wrong_answer", 0, "答案错误，正确答案是：" + correctAnswer);
        }

        return new SubmitResult("wrong_answer", 0, "未知题目类型");
    }

    /**
     * 更新通过率
     */
    private void updateAcceptanceRate(Problem problem) {
        if (problem.getSubmitCount() > 0) {
            double rate = (double) problem.getAcceptedCount() / problem.getSubmitCount() * 100;
            problem.setAcceptanceRate(BigDecimal.valueOf(rate).setScale(2, RoundingMode.HALF_UP));
        }
    }

    /**
     * 更新学习进度
     */
    private void updateProgress(Long userId, Long courseId) {
        UserProgress progress = progressRepository.findByUserIdAndCourseId(userId, courseId)
                .orElse(new UserProgress());

        progress.setUserId(userId);
        progress.setCourseId(courseId);

        long solvedCount = submissionRepository.countAcceptedProblemsByUserIdAndCourseId(userId, courseId);
        long totalCount = problemRepository.countByCourseId(courseId);

        progress.setSolvedCount((int) solvedCount);
        progress.setTotalCount((int) totalCount);
        progress.setLastPracticeTime(java.time.LocalDateTime.now());

        progressRepository.save(progress);
    }

    /**
     * 获取用户对题目的状态
     */
    private String getUserProblemStatus(Long userId, Long problemId) {
        if (userId == null) {
            return null;
        }

        Optional<UserSubmission> submission = submissionRepository
                .findFirstByUserIdAndProblemIdOrderBySubmitTimeDesc(userId, problemId);

        if (submission.isEmpty()) {
            return null;
        }

        return "accepted".equals(submission.get().getStatus()) ? "solved" : "attempted";
    }

    /**
     * 按状态过滤题目列表
     */
    private List<ProblemListResponse.ProblemItem> filterByStatus(List<ProblemListResponse.ProblemItem> list, String status) {
        return list.stream()
                .filter(item -> {
                    if ("solved".equals(status)) {
                        return "solved".equals(item.getStatus());
                    } else if ("unsolved".equals(status)) {
                        return item.getStatus() == null;
                    }
                    return true;
                })
                .collect(Collectors.toList());
    }

    /**
     * 解析JSON数组
     */
    private List<String> parseJsonArray(String json) {
        if (json == null || json.trim().isEmpty()) {
            return new ArrayList<>();
        }
        try {
            return objectMapper.readValue(json, new TypeReference<List<String>>() {});
        } catch (Exception e) {
            logger.error("解析JSON数组失败: {}", json, e);
            return new ArrayList<>();
        }
    }

    /**
     * 解析示例
     */
    private List<ProblemDetailResponse.Example> parseExamples(String json) {
        if (json == null || json.trim().isEmpty()) {
            return new ArrayList<>();
        }
        try {
            return objectMapper.readValue(json, new TypeReference<List<ProblemDetailResponse.Example>>() {});
        } catch (Exception e) {
            logger.error("解析示例失败: {}", json, e);
            return new ArrayList<>();
        }
    }

    /**
     * 解析选项
     */
    private List<ProblemDetailResponse.Option> parseOptions(String json) {
        if (json == null || json.trim().isEmpty()) {
            return null;
        }
        try {
            return objectMapper.readValue(json, new TypeReference<List<ProblemDetailResponse.Option>>() {});
        } catch (Exception e) {
            logger.error("解析选项失败: {}", json, e);
            return null;
        }
    }

    /**
     * 更新连续学习天数
     */
    private void updateContinuousLearningDays(Long userId) {
        User user = userRepository.findById(userId).orElse(null);
        if (user == null) {
            return;
        }

        java.time.LocalDate today = java.time.LocalDate.now();
        java.time.LocalDate lastLearningDate = user.getLastLearningDate();

        Integer continuousDays = user.getContinuousLearningDays();
        if (continuousDays == null) {
            continuousDays = 0;
        }

        if (lastLearningDate == null) {
            // 第一次做题
            continuousDays = 1;
        } else if (lastLearningDate.equals(today)) {
            // 今天已经做过题，不增加
            return;
        } else if (lastLearningDate.equals(today.minusDays(1))) {
            // 昨天做过题，连续天数+1
            continuousDays++;
        } else {
            // 中断了，重置为1
            continuousDays = 1;
        }

        // 更新数据库
        user.setContinuousLearningDays(continuousDays);
        user.setLastLearningDate(today);
        userRepository.save(user);

        logger.info("更新用户 {} 连续学习天数：{}", userId, continuousDays);
    }

    /**
     * 累加用户学习时长
     */
    @Transactional
    private void updateStudyMinutes(Long userId, Integer minutes) {
        try {
            userRepository.incrementStudyMinutes(userId, minutes);
            logger.info("累加用户 {} 学习时长：{} 分钟", userId, minutes);
        } catch (Exception e) {
            logger.error("累加用户学习时长失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 获取随机每日推荐题目（使用题目池+短时间去重）
     */
    public DailyProblemResponse getRandomDailyProblem(Long userId, String difficulty) {
        try {
            // 获取用户最近看过的题目ID列表
            java.util.Set<Long> recentProblemIds = userId != null ? getRecentProblemIds(userId) : new java.util.HashSet<>();
            
            // 从题目池中随机获取一道题目ID（排除最近看过的）
            Long randomProblemId = problemPoolService.getRandomProblemIdFromPoolExcluding(recentProblemIds);
            
            if (randomProblemId == null) {
                logger.warn("从题目池获取题目失败，题库可能为空");
                return null;
            }
            
            // 根据ID查询题目详情
            Problem problem = problemRepository.findById(randomProblemId).orElse(null);
            
            if (problem == null) {
                logger.warn("题目ID {} 不存在或已被删除", randomProblemId);
                return null;
            }
            
            // 如果指定了难度，检查是否匹配
            if (difficulty != null && !difficulty.trim().isEmpty()) {
                if (!difficulty.equalsIgnoreCase(problem.getDifficulty())) {
                    // 难度不匹配，尝试再次获取（最多3次）
                    for (int i = 0; i < 3; i++) {
                        randomProblemId = problemPoolService.getRandomProblemIdFromPoolExcluding(recentProblemIds);
                        if (randomProblemId != null) {
                            problem = problemRepository.findById(randomProblemId).orElse(null);
                            if (problem != null && difficulty.equalsIgnoreCase(problem.getDifficulty())) {
                                break;
                            }
                        }
                    }
                    
                    // 如果还是不匹配，使用原有的随机查询（按难度）
                    if (problem == null || !difficulty.equalsIgnoreCase(problem.getDifficulty())) {
                        logger.debug("题目池中难度匹配失败，使用数据库查询");
                        problem = problemRepository.findRandomProblemByDifficulty(difficulty).orElse(null);
                    }
                }
            }
            
            if (problem == null) {
                logger.warn("没有找到合适的每日推荐题目");
                return null;
            }
            
            // 记录用户看过的题目（防止短时间内重复）
            if (userId != null) {
                addRecentProblem(userId, problem.getId());
            }
            
            // 转换为DTO返回
            return convertToDailyProblemResponse(problem);
            
        } catch (Exception e) {
            logger.error("获取随机每日题目失败", e);
            return null;
        }
    }
    
    /**
     * 获取用户最近看过的题目ID
     */
    private java.util.Set<Long> getRecentProblemIds(Long userId) {
        String key = "user:recent:problems:" + userId;
        java.util.Set<Object> values = redisTemplate.opsForSet().members(key);
        
        if (values == null || values.isEmpty()) {
            return new java.util.HashSet<>();
        }
        
        return values.stream()
            .map(obj -> {
                try {
                    return Long.parseLong(obj.toString());
                } catch (NumberFormatException e) {
                    logger.warn("解析题目ID失败：{}", obj);
                    return null;
                }
            })
            .filter(id -> id != null)
            .collect(java.util.stream.Collectors.toSet());
    }
    
    /**
     * 记录用户看过的题目（防止短时间内重复推荐）
     */
    private void addRecentProblem(Long userId, Long problemId) {
        String key = "user:recent:problems:" + userId;
        
        try {
            // 如果超过限制，移除最旧的（使用Set会自动去重）
            Long size = redisTemplate.opsForSet().size(key);
            if (size != null && size >= RECENT_PROBLEMS_SIZE) {
                // 清空重新开始（简单策略）
                redisTemplate.delete(key);
                logger.debug("用户 {} 最近看过的题目已达上限，清空记录", userId);
            }
            
            // 添加新的题目ID
            redisTemplate.opsForSet().add(key, problemId.toString());
            
            // 设置过期时间（2小时）
            redisTemplate.expire(key, 2, java.util.concurrent.TimeUnit.HOURS);
            
            logger.debug("记录用户 {} 看过题目 {}", userId, problemId);
            
        } catch (Exception e) {
            logger.error("记录用户看过的题目失败", e);
        }
    }

    /**
     * 将Problem实体转换为DailyProblemResponse
     */
    private DailyProblemResponse convertToDailyProblemResponse(Problem problem) {
        // 获取课程名称作为分类
        String category = null;
        try {
            Course course = courseRepository.findById(problem.getCourseId()).orElse(null);
            if (course != null) {
                category = course.getName();
            }
        } catch (Exception e) {
            logger.warn("获取课程名称失败: {}", e.getMessage());
        }
        
        // 解析标签
        List<String> tags = null;
        try {
            if (problem.getTags() != null && !problem.getTags().trim().isEmpty()) {
                tags = objectMapper.readValue(problem.getTags(), new TypeReference<List<String>>() {});
            }
        } catch (Exception e) {
            logger.warn("解析题目标签失败: {}", e.getMessage());
            tags = new ArrayList<>();
        }
        
        return DailyProblemResponse.builder()
            .problemId(problem.getId())
            .title(problem.getTitle())
            .description(problem.getDescription())
            .difficulty(problem.getDifficulty())
            .tags(tags)
            .category(category)
            .build();
    }

    /**
     * 提交结果内部类
     */
    private static class SubmitResult {
        private final String status;
        private final int score;
        private final String feedback;

        public SubmitResult(String status, int score, String feedback) {
            this.status = status;
            this.score = score;
            this.feedback = feedback;
        }

        public String getStatus() {
            return status;
        }

        public int getScore() {
            return score;
        }

        public String getFeedback() {
            return feedback;
        }
    }
}



